﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

namespace System
{
    public static class ObjectByLogExtension
    {
        private static object locker = new object();
        /// <summary>
        /// 获取请求相关信息
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <returns></returns>
        private static List<string> GetRequestData(LogLevel level)
        {
            List<string> lstdata = new List<string>();
            //if (HttpContext.Current != null && HttpContext.Current.Request != null)
            //{
            //    if (HttpContext.Current.Server != null)
            //    {
            //        lstdata.Add("Computer：" + HttpContext.Current.Server.MachineName);
            //    }
            //    HttpRequest Request = HttpContext.Current.Request;
            //    if (Request.Url != null)
            //    {
            //        lstdata.Add("URI：" + Request.Url.AbsoluteUri);
            //    }
            //    if (Request.UrlReferrer != null)
            //    {
            //        lstdata.Add("UrlReferrer：" + Request.UrlReferrer.AbsoluteUri);
            //    }
            //    if (Request.ServerVariables != null)
            //    {
            //        #region 获取IP地址
            //        Regex regex = new Regex("([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}");
            //        string str_Ip = string.Empty;
            //        if (!string.IsNullOrEmpty(Request.ServerVariables["REMOTE_ADDR"]))
            //        {
            //            str_Ip = Request.ServerVariables["REMOTE_ADDR"];
            //        }
            //        else if (!string.IsNullOrEmpty(Request.ServerVariables["HTTP_CDN_SRC_IP"]) && regex.IsMatch(Request.ServerVariables["HTTP_CDN_SRC_IP"]))
            //        {
            //            str_Ip = Request.ServerVariables["HTTP_CDN_SRC_IP"];
            //        }
            //        else if (!string.IsNullOrEmpty(Request.ServerVariables["HTTP_X_FORWARDED_FOR"]) && regex.IsMatch(Request.ServerVariables["HTTP_X_FORWARDED_FOR"]))
            //        {
            //            str_Ip = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            //        }
            //        string[] ip = str_Ip.Split(',');
            //        #endregion
            //        lstdata.Add("IP：" + ip[0]);
            //    }
            //    lstdata.Add("UserAgent：" + Request.UserAgent);
            //    if (level == LogLevel.Warn)
            //    {
            //        lstdata.Add("POST信息：" + GetJsonFromObject(Request.Form));
            //    }
            //    else if (level == LogLevel.Error)
            //    {
            //        lstdata.Add("POST信息：" + GetJsonFromObject(Request.Form));

            //        if (Request.Cookies != null && Request.Cookies.Count > 0)
            //        {
            //            List<string> lstCKInfo = new List<string>();
            //            for (int j = 0; j < Request.Cookies.Count; j++)
            //            {
            //                HttpCookie item = Request.Cookies[j];
            //                lstCKInfo.Add(item.Name + ":" + item.Value);
            //            }
            //            lstdata.Add("Cookie信息：" + string.Join(";", lstCKInfo.ToArray()));
            //        }
            //    }
            //}
            return lstdata;
        }

        /// <summary>
        /// 写入日志
        /// </summary>
        /// <param name="logName">日志名称</param>
        /// <param name="developer">开发记录者</param>
        /// <param name="level">日志级别</param>
        /// <param name="detail">日志详情</param>
        /// <param name="Added">记录时间</param>
        private static void Write(string logName, Developer developer, LogLevel level, string detail, DateTime Added)
        {
            Log log = new Log();
            log.LogName = logName;
            log.Level = level;
            log.Developer = developer;
            //log.ServerInfo = HttpContext.Current.Server.MachineName;
            log.Added = Added;
            List<string> lstDetails = GetRequestData(level);
            lstDetails.Add(detail);
            log.Detail = string.Join("\r\n\r\n", lstDetails.ToArray());


            //todo :可以将日志写入 文件、数据库、MongoDB
            //这里写入根目录 log文件夹
            string logText = GetJsonFromObject(log) + "\r\n";
            string fileName = DateTime.Now.ToString("yyyyMMdd") + ".log";
            string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log");
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            fileName = Path.Combine(dir, fileName);
            File.AppendAllText(fileName, logText, Encoding.UTF8);
        }

        /// <summary>
        /// 写入Info 日志
        /// </summary>
        /// <param name="logName">日志名称</param>
        /// <param name="developer">开发记录者</param>
        /// <param name="Info_objs">日志内容</param>
        public static void LogInfo(this object detail, string logName, Developer developer, params object[] Info_objs)
        {
            lock (locker)
            {
                List<string> lstDetails = new List<string>();
                lstDetails.Add(GetJsonFromObject(detail));
                if (Info_objs != null && Info_objs.Length > 0)
                {
                    List<string> lstInfo = new List<string>();
                    foreach (var item in Info_objs)
                    {
                        lstInfo.Add(GetJsonFromObject(item));
                    }
                    lstDetails.Add("标记信息：" + string.Join(";", lstInfo.ToArray()));
                }
                Write(logName, developer, LogLevel.Info, string.Join("\r\n", lstDetails.ToArray()), DateTime.Now);
            }
        }


        /// <summary>s
        /// 写入带 堆栈执行 的Info 日志
        /// </summary>
        /// <param name="logName">日志名称</param>
        /// <param name="developer">开发记录者</param>
        /// <param name="Info_objs">日志内容</param>
        public static void LogWrite(this object detail, string logName, Developer developer, params object[] Info_objs)
        {
            lock (locker)
            {
                List<string> lstDetails = new List<string>();
                System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(1, true);
                System.Diagnostics.StackFrame frame = stack.GetFrame(0);
                string execFile = frame.GetFileName();
                string fullName = frame.GetMethod().DeclaringType.FullName;
                string methodName = frame.GetMethod().Name;
                int execLine = frame.GetFileLineNumber();
                lstDetails.Add("文件路径：" + execFile + "\r\n");
                lstDetails.Add("类全命名：" + fullName + "\r\n");
                lstDetails.Add("执行方法：" + methodName + "\r\n");
                lstDetails.Add("当前行号：" + execLine + "\r\n");

                lstDetails.Add(GetJsonFromObject(detail));
                if (Info_objs != null && Info_objs.Length > 0)
                {
                    List<string> lstInfo = new List<string>();
                    foreach (var item in Info_objs)
                    {
                        lstInfo.Add(GetJsonFromObject(item));
                    }
                    lstDetails.Add("标记信息：" + string.Join(";", lstInfo.ToArray()));
                }
                Write(logName, developer, LogLevel.Info, string.Join("\r\n", lstDetails.ToArray()), DateTime.Now);
            }
        }

        /// <summary>
        /// 写入Warn 日志
        /// </summary>
        /// <param name="logName">日志名称</param>
        /// <param name="developer">开发记录者</param>
        /// <param name="Info_objs">日志内容</param>
        public static void LogWarn(this object detail, string logName, Developer developer, params object[] Info_objs)
        {
            lock (locker)
            {
                List<string> lstDetails = new List<string>();
                System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(1, true);
                System.Diagnostics.StackFrame frame = stack.GetFrame(0);
                string execFile = frame.GetFileName();
                string fullName = frame.GetMethod().DeclaringType.FullName;
                string methodName = frame.GetMethod().Name;
                int execLine = frame.GetFileLineNumber();
                lstDetails.Add("文件路径：" + execFile + "\r\n");
                lstDetails.Add("类全命名：" + fullName + "\r\n");
                lstDetails.Add("执行方法：" + methodName + "\r\n");
                lstDetails.Add("当前行号：" + execLine + "\r\n");

                lstDetails.Add(GetJsonFromObject(detail));

                if (Info_objs != null && Info_objs.Length > 0)
                {
                    List<string> lstInfo = new List<string>();
                    foreach (var item in Info_objs)
                    {
                        lstInfo.Add(GetJsonFromObject(item));
                    }
                    lstDetails.Add("标记信息：" + string.Join(";", lstInfo.ToArray()));
                }
                Write(logName, developer, LogLevel.Warn, string.Join("\r\n", lstDetails.ToArray()), DateTime.Now);
            }
        }

        /// <summary>
        /// 写入 Errorr日志
        /// </summary>
        /// <param name="logName">日志名称</param>
        /// <param name="developer">开发记录者</param>
        /// <param name="ex">异常对象(可为null)</param>
        /// <param name="ext_InfoObjs">日志内容</param>
        public static void LogError(this Exception ex, string logName, Developer developer, params object[] ext_InfoObjs)
        {
            lock (locker)
            {
                List<string> lstDetails = new List<string>();
                Exception currentEX = ex;

                if (ex != null)
                {
                    lstDetails.Add("Exception：" + ex.ToString());
                }

                if (ex.InnerException != null)
                {
                    lstDetails.Add("InnerException：" + ex.ToString());
                }
                StringBuilder sb_extInfo = new StringBuilder();
                if (ext_InfoObjs != null && ext_InfoObjs.Length > 0)
                {
                    List<string> lst_ext_Inf = new List<string>();
                    foreach (var item in ext_InfoObjs)
                    {
                        lst_ext_Inf.Add(GetJsonFromObject(item));
                    }
                    lstDetails.Add("标记信息：" + string.Join(";", lst_ext_Inf.ToArray()));
                }
                string detail = string.Join("\r\n\r\n", lstDetails.ToArray());
                Write(logName, developer, LogLevel.Error, detail, DateTime.Now);
            }
        }


        #region  private 反射 对象

        private static bool IsSimpleType(Type type)
        {
            Type t = Nullable.GetUnderlyingType(type) ?? type;
            if (t.IsPrimitive
                || t.IsEnum
                || t == typeof(string)
                || t.IsAssignableFrom(typeof(Guid))
                || t.IsAssignableFrom(typeof(DateTime))
                ) return true;
            return false;
        }

        private static JavaScriptSerializer JSS = new JavaScriptSerializer();
        private static string GetJsonFromObject(object obj)
        {
            if (obj == null)
            {
                return string.Empty;
            }
            string result = string.Empty;
            Type type = obj.GetType();
            if (IsSimpleType(type))
            {
                return obj.ToString();
            }
            else if (obj is NameValueCollection)
            {
                List<string> lstItem = new List<string>();
                NameValueCollection nvc = (NameValueCollection)obj;
                foreach (var key in nvc.AllKeys)
                {
                    lstItem.Add("\"" + key + "\":\"" + nvc[key] + "\"");
                }
                result = "{" + string.Join(",", lstItem) + "}";
            }
            else
            {
                result = JSS.Serialize(obj);
            }
            return result;
        }

        #endregion
    }
    /// <summary>
    /// 程序日志
    /// </summary>
    public class Log
    {
        public Guid Id { get { return Guid.NewGuid(); } }

        /// <summary>
        /// 日志名称
        /// </summary>
        public string LogName { get; set; }

        /// <summary>
        /// 日志级别
        /// </summary>
        public LogLevel Level { get; set; }

        /// <summary>
        /// 当前记录日志者
        /// </summary>
        public Developer Developer { get; set; }

        /// <summary>
        /// 服务器信息（如：服务器名称、服务器IP）
        /// </summary>
        public string ServerInfo { get; set; }

        /// <summary>
        /// 日志详细内容
        /// </summary>
        public string Detail { get; set; }

        /// <summary>
        /// 日志时间
        /// </summary>     
        public DateTime Added { get; set; }

    }

    /// <summary>
    /// 日志级别
    /// </summary>
    public enum LogLevel
    {
        Info = 0,
        Warn = 1,
        Error = 2
    }

    /// <summary>
    /// 日志记录开发者
    /// </summary>
    public enum Developer
    {
        /// <summary>
        /// 系统默认
        /// </summary>
        SysDefault = 0,

        /// <summary>
        /// 其他用户
        /// </summary>
        XiaoQiang = 115
    }
}


